export class ContentEventerData {
    private _value: any;
    public type: ContentEventerDataType = 'normal';
    constructor(typeOrVal: ContentEventerDataType | { [k: string]: any }, val?: any) {
        if (typeof typeOrVal === 'string') {
            this.type = typeOrVal as ContentEventerDataType;
            this._value = val;
        } else {
            this.type = typeOrVal.type;
            this._value = typeOrVal._value;
        }
    }
    public get value() {
        if (this.type === 'dom') {
            return window.document.querySelector(this._value);
        }
        return this._value;
    }

    public set value(val: any) {
        this._value = val
    }
}
/**
 * 内容脚本自定义事件
 */
export namespace ContentEventer {
    const EVENTS_ID = 'content_event';
    const EVENTS_OUT = '_out';
    const EVENTS_IN = '_in';
    const EVENTS_RETURN = '_return';
    const TIMEOUT = 1000 * 10;

    const events: ContentEventerHandler[] = []

    /**
     * 仅发送事件
     * @param msg 
     */
    export function send(msg: ContentMessage, out = true) {
        const outMsg = { ...msg };
        if (out) {
            outMsg.type += EVENTS_OUT;
        } else {
            outMsg.type += EVENTS_IN;
        }
        const event = new CustomEvent(EVENTS_ID, {
            detail: outMsg
        });
        window.dispatchEvent(event);
    }

    /**
     * 异步信息发送
     * @param msg 
     * @returns 
     */
    export function sendMessage<T>(msg: ContentMessage): Promise<T> {
        return new Promise((resolve, reject) => {

            const timer = setTimeout(() => {
                window.removeEventListener(EVENTS_ID, handler);
                reject('time out')
            }, TIMEOUT)
            const handler = (e: any) => {
                const inMsg: ContentMessage = e.detail;
                if (inMsg.type !== msg.type + EVENTS_IN) {
                    return
                }
                window.removeEventListener(EVENTS_ID, handler);
                clearTimeout(timer);
                resolve(inMsg.data as T);
            }
            window.addEventListener(EVENTS_ID, handler);

            send(msg)
        })
    }

    /**
     * 同步信息发送
     * @param msg 
     * @returns 
     */
    export function sendMessageSync<T>(msg: ContentMessage) {
        const timer = setTimeout(() => {
            window.removeEventListener(EVENTS_ID, handler);
            throw Error('time out')
        }, TIMEOUT)
        let res: any
        const handler = (e: any) => {
            const inMsg: ContentMessage = e.detail;
            if (!inMsg) {
                return
            }
            if (inMsg.type !== msg.type + EVENTS_IN) {
                return
            }

            clearTimeout(timer)
            const data = new ContentEventerData(inMsg.data);
            res = data.value;

            window.removeEventListener(EVENTS_ID, handler);
        }
        window.addEventListener(EVENTS_ID, handler);
        send(msg)

        return res as T
    }

    export function initEvents() {
        window.addEventListener(EVENTS_ID, (e: any) => {
            const inMsg: ContentMessage = e.detail;
            if (!inMsg) {
                return
            }
            if (!inMsg.type.endsWith(EVENTS_OUT)) {
                return
            }
            const outMsg = { ...inMsg };
            events.forEach(handler => {
                handler(outMsg)
            })
        });
    }

    export function getOriginType(t: string) {
        return t.replace(EVENTS_OUT, '').replace(EVENTS_IN, '').replace(EVENTS_RETURN, '');
    }

    export function addListener(handler: ContentEventerHandler) {
        const index = events.findIndex(h => h === handler);
        if (index > -1) {
            return
        }
        events.push(handler);
    }

    export function removeListener(handler: ContentEventerHandler) {
        const index = events.findIndex(h => h === handler);
        events.splice(index, 1);
    }
}